import api_client
from flask import Flask, request, jsonify
import json
from datetime import datetime, timedelta
import base64
import os
import logging
import difflib
from collections import deque
import xml.etree.ElementTree as ET
from api_client import APIClient
from xopenai import OpenAIClient
import time
import re
import threading
import chess_png
import requests

from logger_config import logger

app = Flask(__name__)

def load_app_config():
    """加载应用配置文件"""
    try:
        with open('app.conf', 'r') as f:
            return json.load(f)
    except Exception as e:
        logger.error(f"加载应用配置文件时出错: {str(e)}")
        return None

def load_config():
    """加载应用配置文件"""
    try:
        with open('config.json', 'r') as f:
            return json.load(f)
    except Exception as e:
        logger.error(f"加载应用配置文件时出错: {str(e)}")
        return None


class MessageHandler:
    def __init__(self):
        self.config = load_config()
        self.api_client = None
        self.image_dir = 'received_images'
        if not os.path.exists(self.image_dir):
            os.makedirs(self.image_dir)
        # 添加消息缓存，用于存储最近10分钟的消息
        self.recent_messages = deque(maxlen=100)  # 限制缓存大小

    def set_api_client(self, client):
        """设置API客户端"""
        self.api_client = client
        
    def check_keywords(self, content, filters):
        """检查消息内容是否匹配关键词过滤器
        Args:
            content: 消息内容
            filters: 过滤器配置
        Returns:
            bool: 是否匹配
        """
        if not content:
            return True
        # 检查包含关键词
        keywords = filters.get('keywords', [])
        if keywords:
            if not any(keyword.lower() in content.lower() for keyword in keywords):
                logger.info(f"消息内容不包含任何关键词 {keywords}")
                return False
        # 检查排除关键词
        exclude_keywords = filters.get('excludeKeywords', [])
        if exclude_keywords:
            if any(keyword.lower() in content.lower() for keyword in exclude_keywords):
                logger.info(f"消息内容包含排除关键词 {exclude_keywords}")
                return False                
        return True

    def process_new_message(self, message_data, msg_from):
        return message_data

    def get_message_content(self, message_data, msg_type):
        """获取消息内容用于关键词匹配
        Args:
            message_data: 消息数据
            msg_type: 消息类型
        Returns:
            str: 消息内容
        """
        try:
            if msg_type == 1:  # 文本消息
                return message_data.get('Content', {}).get('string', '')
            elif msg_type == 49:  # 链接消息
                xml_content = message_data.get('Content', {}).get('string', '')
                if xml_content:
                    root = ET.fromstring(xml_content)
                    appmsg = root.find('appmsg')
                    if appmsg is not None:
                        # 提取标题和描述
                        title = appmsg.find('title')
                        desc = appmsg.find('des')
                        content_parts = []
                        if title is not None and title.text:
                            content_parts.append(title.text)
                        if desc is not None and desc.text:
                            content_parts.append(desc.text)
                        return ' '.join(content_parts)
            return ''
        except Exception as e:
            logger.error(f"提取消息内容时出错: {str(e)}")
            return ''

    def get_active_forwarders(self, from_wxid, msg_type, message_data=None):
        """获取适用于当前消息的转发器
        Args:
            from_wxid: 消息来源ID
            msg_type: 消息类型
            message_data: 消息数据，用于关键词过滤
        Returns:
            list: 适用的转发器列表
        """
        if not self.config or 'forwarders' not in self.config:
            return []
        active_forwarders = []
        msg_type_map = {
            1: "text",    # 文本消息
            3: "image",   # 图片消息
            43: "video",  # 视频消息
            49: "link"    # 链接消息
        }
        current_msg_type = msg_type_map.get(msg_type)
        if not current_msg_type:
            logger.info(f"未知消息类型: {msg_type}")
            return []
        for forwarder in self.config['forwarders']:
            # 检查转发器是否启用
            if not forwarder.get('enabled', True):
                # logger.info(f"转发器[{forwarder['name']}]未启用，跳过")
                continue   
            # 检查消息来源是否匹配
            if from_wxid not in forwarder['sourceIds']:
                # logger.info(f"消息来源 {from_wxid} 不在转发器[{forwarder['name']}]的sourceIds中，跳过")
                continue   
            # 检查消息类型是否匹配
            filters = forwarder.get('filters', {})
            message_types = filters.get('messageTypes', [])
            # 如果没有指定消息类型，则接受所有类型
            if message_types and current_msg_type not in message_types:
                # logger.info(f"消息类型 {current_msg_type} 不在转发器[{forwarder['name']}]的允许类型{message_types}中，跳过")
                continue  
            # 检查关键词过滤
            if message_data and (filters.get('keywords') or filters.get('excludeKeywords')):
                content = self.get_message_content(message_data, msg_type)
                if not self.check_keywords(content, filters):
                    logger.info(f"转发器[{forwarder['name']}]的关键词过滤不匹配，跳过")
                    continue  
            logger.info(f"转发器[{forwarder['name']}]匹配成功")
            active_forwarders.append(forwarder)
        return active_forwarders

    def forward_message(self, message_data, msg_type, forwarders, from_wxid):
        """根据转发器配置转发消息
        Args:
            message_data: 消息数据
            msg_type: 消息类型
            forwarders: 转发器列表
        Returns:
            dict: 转发结果
        """
        if not forwarders:
            return {"status": "success", "forwarded_count": 0, "total_targets": 0}
        success_count = 0
        total_targets = sum(len(f['targetIds']) for f in forwarders)
        content = ''
        if msg_type == 1:  # 文本消息
            content = self.process_new_message(message_data.get('Content', {}).get('string', ''), from_wxid)
        for forwarder in forwarders:
            # for target_id in forwarder['targetIds']:
            try:
                if msg_type == 49:  # 链接消息
                    xml_content = message_data.get('Content', {}).get('string', '')
                    if self.api_client.forward_url_batch(forwarder['targetIds'], xml_content):
                        success_count += 1
                        logger.info(f"消息通过转发器[{forwarder['name']}]转发成功: {forwarder['targetIds']}")
                elif msg_type == 1:  # 文本消息
                    # content = self.process_new_message(message_data.get('Content', {}).get('string', ''), from_wxid)
                    if content:
                        if self.api_client.send_text_batch(forwarder['targetIds'], content):
                            success_count += 1
                            logger.info(f"消息通过转发器[{forwarder['name']}]转发成功: {forwarder['targetIds']}")
                elif msg_type == 3:  # 图片消息
                    xml_content = message_data.get('Content', {}).get('string', '')
                    if self.api_client.forward_image_batch(forwarder['targetIds'], xml_content):
                        success_count += 1
                        logger.info(f"消息通过转发器[{forwarder['name']}]转发成功: {forwarder['targetIds']}")
                elif msg_type == 43:  # 视频消息
                    xml_content = message_data.get('Content', {}).get('string', '')
                    if self.api_client.forward_video_batch(forwarder['targetIds'], xml_content):
                        success_count += 1
                        logger.info(f"消息通过转发器[{forwarder['name']}]转发成功: {forwarder['targetIds']}")
            except Exception as e:
                logger.error(f"转发器[{forwarder['name']}]转发消息失败: {str(e)}")
        return {
            "status": "success",
            "forwarded_count": success_count,
            "total_targets": total_targets
        }

    def ask_me_mode(self, message, from_wxid):
        content = message.get('Content', {}).get('string', '')
        content = content.replace('@' + self.config['me']['name'], '', 1)
        content = content.replace(self.config['me']['name'], '', 1)
        content = content.lstrip()
        logger.info(content)
        if content.startswith('pgn'):
            count = int(content[3:])
            filename = chess_png.getPuzzleA4(count)
            logger.info('生成pgn:'+filename)
            self.api_client.send_img(from_wxid, filename)
            # self.api_client.send_img(from_wxid, "http://sqe1xn71h.hb-bkt.clouddn.com/PsdCG2FsBjtX_grayscale.png")
            return {"status": "ignored", "reason": "http"}
        if content.startswith('1.'):
            res=chess_png.process_zhisaiwang_data(content)
            if res:
                self.api_client.send_text(from_wxid, res)
                return {"status": "ignored", "reason": "missing data"} 

        client = OpenAIClient()
        cc = content.split('\n')
        if len(cc) > 1:
            fromuser = cc[0]
            ask = cc[1].replace('@' + self.config['me']['name'], '', 1)
            answer = client.query(fromuser, ask)
            logger.info(answer)
            res = answer
            if res:
                self.api_client.send_text(from_wxid, res)
        if len(cc) == 1:
            fromuser = cc[0]
            ask = cc[0].replace(self.config['me']['name'], '', 1)
            answer = client.query(from_wxid, ask)
            logger.info(answer)
            res = answer
            if res:
                self.api_client.send_text(from_wxid, res)
        return {"status": "ignored", "reason": "missing data"}
    
    def send(self, message, towxid):
        self.api_client.send_text(towxid, message)

    def process_message(self, message1):
        """处理接收到的消息"""
        try:
            if message1.get('testMsg'):
                return {"status": "ignored", "reason": "test message"}
            if not message1.get('Data'):
                return {"status": "ignored", "reason": "missing data"}
            message = message1.get('Data')
            msg_type = message.get('MsgType')
            from_wxid1 = message.get('FromUserName')
            create_time = datetime.fromtimestamp(message.get('CreateTime', 0))
            # logger.info("{msg_type} {from_wxid1}".format(msg_type=msg_type, from_wxid1=from_wxid1))
            if from_wxid1:
                from_wxid = from_wxid1.get('string')
                if from_wxid == 'wxid_nbr03z576pi122':
                    return {"status": "ignored", "reason": "myself msg"}
            self.config = load_config()
            logger.info("\n" + "="*50)
            logger.info(f"收到新消息:{create_time}")
            logger.info("-"*50)
            logger.info(json.dumps(message1, ensure_ascii=False, indent=2))
            logger.info("="*50)
            # 检查配置
            if not self.config:
                return {"status": "error", "error": "missing configuration"}
            if (datetime.now() - create_time).total_seconds() > 120:
                logger.info(f"忽略超过2分钟的消息: {create_time} ")
                return {"status": "ignored", "reason": "too old message"}
            if msg_type == 1:
                if from_wxid in self.config.get('whiteRooms', []) and \
                    '@' + self.config['me']['name'] in message.get('Content', {}).get('string', ''):
                    logger.info("Ask me mode activated")
                    return self.ask_me_mode(message, from_wxid)
                if from_wxid in self.config.get('whitePersons', []) and \
                    self.config['me']['name'] in message.get('Content', {}).get('string', ''):
                    logger.info("Ask me mode activated")
                    return self.ask_me_mode(message, from_wxid)
            # 非应答模式，进入转发模式
            active_forwarders = self.get_active_forwarders(from_wxid, msg_type, message)
            # 如果没有适用的转发器，检查传统配置
            if active_forwarders:
                # if not self.config.get('fromUid'):
                #     return {"status": "error", "error": "fromUid not configured"}
                # if not isinstance(self.config['fromUid'], list):
                #     self.config['fromUid'] = [self.config['fromUid']]
                # logger.info('wxfromuis:{form_wxid}  configfromUid:{configfromUid}'.format(
                #     form_wxid=from_wxid, configfromUid=self.config['fromUid']))
                # if from_wxid not in self.config['fromUid']:
                #     logger.info(f"忽略非目标用户消息: {from_wxid}")
                #     return {
                #         "status": "ignored",
                #         "reason": f"message not from configured users: {from_wxid}"
                #   }
                # 处理消息
                if msg_type == 49:  # 链接消息
                    result = self.handle_link_message(message)
                    if result["status"] == "success":
                        forward_result = self.forward_message(message, msg_type, active_forwarders, from_wxid)
                        result["forwarder_results"] = forward_result
                    return result
                elif msg_type == 1:  # 文本消息
                    result = self.handle_text_message(message)
                    if result["status"] == "success":
                        forward_result = self.forward_message(message, msg_type, active_forwarders, from_wxid)
                        result["forwarder_results"] = forward_result
                    return result
                elif msg_type == 3:  # 图片消息
                    result = self.handle_image_message(message)
                    if result["status"] == "success":
                        forward_result = self.forward_message(message, msg_type, active_forwarders, from_wxid)
                        result["forwarder_results"] = forward_result
                    return result
                elif msg_type == 43:  # 图片消息
                    result = self.handle_image_message(message)
                    if result["status"] == "success":
                        forward_result = self.forward_message(message, msg_type, active_forwarders, from_wxid)
                        result["forwarder_results"] = forward_result
                    return result
                else:
                    logger.info(f"忽略未知类型消息: {msg_type}")
                    return {"status": "ignored", "reason": f"unsupported message type: {msg_type}"}
        except Exception as e:
            logger.error(f"处理消息时出错: {str(e)}", exc_info=True)
            return {"status": "error", "error": str(e)}

    def is_similar_message(self, content1, content2, threshold=0.8):
        """
        比较两条消息的相似度
        Args:
            content1: 第一条消息内容
            content2: 第二条消息内容
            threshold: 相似度阈值，默认0.8
        Returns:
            bool: 是否相似
        """
        if not content1 or not content2:
            return False
        
        # 使用difflib计算相似度
        similarity = difflib.SequenceMatcher(None, content1, content2).ratio()
        return similarity >= threshold

    def is_duplicate_message(self, content):
        """
        检查是否是重复消息
        Args:
            content: 消息内容
            create_time: 消息创建时间
        Returns:
            bool: 是否重复
        """
        current_time = datetime.now()
        cutoff_time = current_time - timedelta(minutes=10)
        
        # 清理超过10分钟的消息
        while self.recent_messages and self.recent_messages[0][1] < cutoff_time:
            self.recent_messages.popleft()
        
        # 检查是否有相似消息
        for msg_content, msg_time in self.recent_messages:
            if self.is_similar_message(content, msg_content):
                return True
        
        # 添加新消息到缓存
        self.recent_messages.append((content, current_time))
        return False

    def handle_link_message(self, data):
        """处理链接消息"""
        # 包含小程序，公众号等消息
        try:
            # 获取XML内容
            xml_content1 = data.get('Content')
            xml_content = xml_content1.get('string')
            if not xml_content:
                return {"status": "error", "error": "empty content"}

            # 解析XML
            root = ET.fromstring(xml_content)
            logger.info(f"XML内容: {xml_content}")

            # root就是msg标签，直接查找appmsg
            appmsg = root.find('appmsg')
            if appmsg is None:
                logger.error("找不到appmsg标签")
                return {"status": "error", "error": "missing appmsg tag"}

            # 获取消息类型
            msg_type = appmsg.find('type')
            if msg_type is None or (msg_type.text != '5' and msg_type.text != '33' and msg_type.text != '36' and msg_type.text != '51' and msg_type.text != '6'):
                logger.info(f"不是链接消息，类型: {msg_type.text if msg_type is not None else 'unknown'}")
                return {"status": "ignored", "reason": "not a link message"}
                
            # 获取链接信息
            title = appmsg.find('title').text if appmsg.find('title') is not None else ''
            url = appmsg.find('url').text if appmsg.find('url') is not None else ''
            logger.info(f"处理链接消息: {title} - {url}")

            if msg_type.text == '6':
                # self.api_client.down_file(xml_content)
                return {"status": "ignored", "reason": "file message"}


            # 转发消息到配置的目标用户
            # if self.config and self.api_client and self.config.get('toUids'):
            #     success_count = 0
            #     for to_wxid in self.config['toUids']:
            #         if msg_type.text != '5':
            #             if self.api_client.forward_url(to_wxid, xml_content):
            #                 success_count += 1
            #                 logger.info(f"消息转发成功: {to_wxid}")
            #             else:
            #                 logger.error(f"消息转发失败: {to_wxid}")
            #         else:
            #             if self.api_client.forward_url(to_wxid, xml_content):
            #                 success_count += 1
            #                 logger.info(f"消息转发成功: {to_wxid}")
            #             else:
            #                 logger.error(f"消息转发失败: {to_wxid}")
            #     return {
            #         "status": "success",
            #         "forwarded_count": success_count,
            #         "total_targets": len(self.config['toUids'])
            #     }
            # else:
            #     return {"status": "error", "error": "missing configuration or api client"}
            return {"status": "success", "forwarded_count": 0, "total_targets": 0}
        except ET.ParseError as e:
            logger.error(f"XML解析错误: {str(e)}")
            return {"status": "error", "error": f"xml parse error: {str(e)}"}
        except Exception as e:
            logger.error(f"处理链接消息时出错: {str(e)}", exc_info=True)
            return {"status": "error", "error": str(e)}

    def handle_text_message(self, data):
        """处理文本消息"""
        try:
            msg_data = data
            content = msg_data.get("Content", {}).get("string", "")
            from_user = msg_data.get("FromUserName", {}).get("string", "")
            to_user = msg_data.get("ToUserName", {}).get("string", "")
            create_time = msg_data.get("CreateTime", 0)
            msg_type = msg_data.get("MsgType", 0)

            # 只处理文本消息
            if msg_type != 1:
                logger.info(f"\n忽略非文本消息: {msg_type}")
                return {"status": "ignored", "reason": "not text message"}

         

            # 打印格式化的消息详情
            logger.info(format_message(msg_data))

            # 获取适用的转发器
            # forwarders = self.get_active_forwarders(from_user, msg_type, msg_data)
            # if forwarders:
            #     # 转发消息
            #        # 检查是否是重复消息
            #     if self.is_duplicate_message(content, create_time):
            #         logger.info(f"\n检测到重复消息，已忽略: {content}")
            #         return {"status": "ignored", "reason": "duplicate message"}
            #     return self.forward_message(msg_data, msg_type, forwarders, from_user)

            return {"status": "success"}

        except Exception as e:
            logger.error(f"处理文本消息时出错: {str(e)}", exc_info=True)
            return {"status": "error", "error": str(e)}

    def handle_image_message(self, data):
        """处理图片消息"""
        try:
            msg_data = data
            from_user = msg_data.get("FromUserName", {}).get("string", "")
            msg_id = msg_data.get("MsgId", "unknown")
            content1 = msg_data.get("Content", {})
            content = content1.get("string", "")
            img_buf = msg_data.get("ImgBuf", {})

            # 解析XML内容获取图片信息
            try:
                logger.info(f"XML内容: {content}")
                root = ET.fromstring(content)
                img_element = root.find('img')
                if img_element is not None:
                    cdn_thumb_url = img_element.get('cdnthumburl', '')
                    aes_key = img_element.get('aeskey', '')
                    length = img_element.get('length', '')
                    md5 = img_element.get('md5', '')
                else:
                    cdn_thumb_url = ''
                    aes_key = ''
                    length = ''
                    md5 = ''
            except ET.ParseError:
                logger.error("解析图片XML内容失败")
                cdn_thumb_url = ''
                aes_key = ''
                length = ''
                md5 = ''

            # 保存缩略图
            if img_buf and 'buffer' in img_buf:
                try:
                    img_data = base64.b64decode(img_buf['buffer'])
                    filename = f"{msg_id}_{md5[:8]}_thumb.jpg"
                    filepath = os.path.join(self.image_dir, filename)
                    with open(filepath, 'wb') as f:
                        f.write(img_data)
                    logger.info(f"\n缩略图已保存: {filepath}")
                except Exception as e:
                    logger.error(f"保存缩略图失败: {str(e)}")

            # 打印图片消息详情
            logger.info(f"""
图片消息详情:
- 消息ID: {msg_id}
- 发送者: {from_user}
- 接收者: {msg_data.get('ToUserName', {}).get('string')}
- 发送时间: {datetime.fromtimestamp(msg_data.get('CreateTime', 0))}
- CDN缩略图URL: {cdn_thumb_url}
- AES密钥: {aes_key}
- 文件大小: {length}
- MD5: {md5}
- 缩略图大小: {img_buf.get('iLen', 0)} bytes
""")

            return {"status": "success"}

        except Exception as e:
            logger.error(f"处理图片消息时出错: {str(e)}", exc_info=True)
            return {"status": "error", "error": str(e)}


def format_message(msg_data):
    """格式化消息内容"""
    return f"""
消息详情:
- 消息ID: {msg_data.get('MsgId')}
- 发送者: {msg_data.get('FromUserName', {}).get('string')}
- 接收者: {msg_data.get('ToUserName', {}).get('string')}
- 消息类型: {msg_data.get('MsgType')}
- 发送时间: {datetime.fromtimestamp(msg_data.get('CreateTime', 0))}
- 消息内容: {msg_data.get('Content', {}).get('string')}
- 推送内容: {msg_data.get('PushContent')}
"""


def ensure_login():
    """确保登录成功"""
    client = APIClient()
    # if not client.check_online:

    # 检查是否在线
    if not client.check_online:
        logger.info("\n未登录，开始登录流程...")
        # 获取登录二维码
        qr_data = client.get_login_qrcode()
        if qr_data:
            client.display_qrcode(qr_data)
            logger.info("\n请扫描二维码登录...")

            # 等待扫码并检查登录状态
            while True:
                status = client.check_login_status()
                if status == 1:  # 已扫码，等待确认
                    logger.info("\n已扫码，等待确认...")
                elif status == 2:  # 已确认
                    logger.info("\n登录成功！")
                    break
                elif status == 0:  # 未扫码
                    logger.info("\n等待扫码...")
                time.sleep(5)
        else:
            logger.error("获取二维码失败")
            return None

    logger.info("\n登录状态检查完成")
    return client


def start_message_service(client):
    """启动消息服务"""
    try:
        # 加载应用配置
        app_config = load_app_config()
        if not app_config:
            logger.error("无法加载应用配置，使用默认配置")
            port = 5000
            host = '172.17.0.1'
            callback_host = '172.17.0.1'
        else:
            msg_config = app_config['message_service']
            port = msg_config['port']
            host = msg_config['host']
            callback_host = msg_config['callback_host']

        # 创建一个线程来设置回调
        def set_callback_after_start():
            # 等待服务器启动
            time.sleep(2)
            # 设置回调地址
            callback_url = f"http://{callback_host}:{port}/message"
            if client.set_callback(callback_url):
                logger.info(f"\n回调地址设置成功: {callback_url}")
            else:
                logger.error("设置回调地址失败")

        callback_thread = threading.Thread(target=set_callback_after_start)
        callback_thread.daemon = True
        callback_thread.start()

        # 启动Flask服务
        logger.info(f"\n开始启动消息服务在 {host}:{port}...")
        app.debug = True
        app.run(host=host, port=port)

    except Exception as e:
        logger.error(f"启动消息服务时出错: {str(e)}", exc_info=True)

# 创建消息处理器实例
message_handler = MessageHandler()

@app.route('/message', methods=['POST'])
def receive_message():
    """接收消息的接口"""
    try:
        message = request.get_json()
        if not message:
            return jsonify({"status": "error", "error": "empty message"}), 400
            
        # 处理消息
        if message.get('Appid'):
            if message['Appid'] == 'wx_tDRvpO2Txxxxxxxx':
                # 转发到本机 3000 端口

                try:
                    forward_url = "http://172.17.0.1:5001/message"
                    response = requests.post(forward_url, json=message)
                    logger.info(f"转发消息到 {forward_url}: {response.text}")
                    if response.status_code != 200:
                        logger.error(f"转发消息到 {forward_url} 时出错: {response.text}")
                    return response.json(), 200
                except Exception as e:
                    logger.error(f"转发消息时出错: {str(e)}", exc_info=True)
                    return jsonify({"status": "error", "error": str(e)}), 500
            else:
                result = message_handler.process_message(message)
                return jsonify(result), 200
        return jsonify({"status": "error", "error": "no process"}), 500
    except Exception as e:
        logger.error(f"接收消息时出错: {str(e)}", exc_info=True)
        return jsonify({"status": "error", "error": str(e)}), 500

@app.route('/sendmessage', methods=['POST'])
def send_message():
    """接收消息的接口"""
    try:
        message = request.get_json()
        if not message:
            return jsonify({"status": "error", "error": "empty message"}), 400
        message_handler.send(message.get('report'),"1234@chatroom")
        return jsonify({"status": "ok"}), 200
    except Exception as e:
        logger.error(f"接收消息时出错: {str(e)}", exc_info=True)
        return jsonify({"status": "error", "error": str(e)}), 500
    # return jsonify({"status": "error"}), 500

if __name__ == '__main__':
    # 确保登录成功
    client = ensure_login()
    if client:
        # 设置API客户端
        message_handler.set_api_client(client)
        # 启动消息服务
        start_message_service(client)     
    else:
        logger.error("登录失败，无法启动消息服务")